#include <stdio.h>
#include <ctype.h>
#include "tar.h"
#include "dir.h"


#if !defined(WITH_PWD)
char *DownPath(char *Path, char *DownTo, char **PathSteps, int *Depth) {
  char *cp;

  PathSteps = realloc(PathSteps, ++(*Depth));
  cp = Path;
  while (*cp) {
    ++cp;
  }
  PathSteps[(*Depth) - 1] = cp;
  strcat(cp, DownTo);
} /* DownPath */


char *UpPath(char *Path, char **PathSteps, int *Depth) {
  if (*Depth > 0) {
    *(PathSteps[--(*Depth)]) = '\0';
    PathSteps = realloc(PathSteps, *Depth);
  } else {
    fprintf(stderr,"tar: warning: trying to move further up than top of path!\n");
  }
  return Path;
} /* UpPath */
#endif


#if WITH_PWD
void ChangeCurrentDir(char *Name) {
  while (!chkos(os_swi2(os_X | OS_FSControl,0,(int)Name)));
} /* ChangeCurrentDir */
#endif


static char *ReadFSInfo(int Action, int LengthPos, int NameStart) {
  os_gbpbstr Blk;
  static char Data[256];

  do {
    Blk.action = Action;
    Blk.file_handle = 0;
    Blk.data_addr = (void *)Data;
    Blk.buf_len = 256;
  } while (!chkos(os_gbpb(&Blk)));
  Data[Data[LengthPos] + NameStart] = '\0';
  return &Data[NameStart];
} /* ReadFSInfo */


#if WITH_PWD
int Unset;


int CurrentDirUnset() {
  return (strcmp(ReadFSInfo(6,1,2), "\"Unset\"") == 0) ? 1 : 0;
} /* CurrentDirUnset */


char *GetCurrentDir(char *CurrentDirName) {
  char *cp;
  os_regset Regs;
  int FSNumber;
  char FSName[256];

  if (UseCanonicalisedPaths) {
    Regs.r[0] = 37;
    Regs.r[1] = (int)"@";
    Regs.r[2] = (int)FSName;
    Regs.r[3] = 0;
    Regs.r[4] = 0;
    Regs.r[5] = sizeof(FSName);
    if (os_swix(OS_FSControl, &Regs) == NULL) {
      strcpy(CurrentDirName, FSName);
      return CurrentDirName;
    }
  }

  *CurrentDirName = '\0';
  do {
    cp = ReadFSInfo(6,1,2);
    if (*CurrentDirName) {
      strcat(cp,".");
      strcat(cp,CurrentDirName);
    }
    strcpy(CurrentDirName,cp);
    ChangeCurrentDir("\\");
    ChangeCurrentDir("\\.^");
  } while (*CurrentDirName != '$' && *CurrentDirName != 0);
  if (*CurrentDirName == 0) {
    return NULL;
  }
  cp = ReadFSInfo(5,0,1);
  strcat(cp,".");
  strcat(cp,CurrentDirName);
  strcpy(CurrentDirName,cp);
  do {
    Regs.r[0] = 0;
    Regs.r[1] = 0;
    Regs.r[2] = 0;
  } while (!chkos(os_args(&Regs)));
  FSNumber = Regs.r[0];
  do {
    Regs.r[0] = 33;
    Regs.r[1] = FSNumber;
    Regs.r[2] = (int)FSName;
    Regs.r[3] = 256;
  } while (!chkos(os_swix(OS_FSControl,&Regs)));
  strcat(FSName,"::");
  strcat(FSName,CurrentDirName);
  strcpy(CurrentDirName,FSName);
  ChangeCurrentDir("\\");
  ChangeCurrentDir(CurrentDirName);
  return(CurrentDirName);
} /* GetCurrentDir */
#endif


int MakeDir(char *Name) {
  return(((os_swi2(os_X | OS_File, 8, (int)Name)) != NULL) ? -1 : 0);
} /* MakeDir */


static char Buffer[MAXPATHLEN];

int name_to_unix(char *Name) {
  char *LastSep, *cp, *Ext;

  LastSep = NULL;
  Ext = Name;
  cp = Name;
  while (*cp) {
    if (*cp == FS_DIRSEP) {
      if (LastSep != NULL)
        Ext = LastSep + 1;
      LastSep = cp;
      *cp = UNIX_DIRSEP;
    } else if (*cp == UNIX_DIRSEP)
      *cp = FS_DIRSEP;
    else if (ConvertExclamationMark && *cp == '!')
      *cp = '_';
    cp++;
  }
  if (SwapExtensionToDir && LastSep != NULL) {
    *LastSep = '\0';
    if (strlen(Ext) > MaxExtLength)
      *LastSep = UNIX_DIRSEP;
    else {
      if (*(LastSep + 1) == '\0')
        return 0;
      strcpy(Buffer,Ext);
      *Ext = 0;
      strcpy(Ext,LastSep + 1);
      strcat(Name,".");
      strcat(Name,Buffer);
    }
  }
  return 1;
} /* name_to_unix */


static int chktruncate(char *leaf, char *rest) {
  int len, n, i;
  char *cp, *cp2;

  n = 0;
  if (MaxLeafLength > 0 &&
      (len = strlen(leaf)) > MaxLeafLength) {
    fprintf(stderr,"tar: shorten: %s -> ",leaf);
    cp = leaf;
    while (*cp && len > MaxLeafLength) {
      switch (*cp) {
        case 'a':
        case 'e':
        case 'i':
        case 'o':
        case 'u':
        case '-':
        case '_':
          if (cp != leaf) {
            n += 1;
            len -= 1;
            cp2 = cp + 1;
            while (*cp2) {
              *(cp2 - 1) = *cp2;
              cp2++;
            }
            *(cp2 - 1) = 0;
            break;
          }
        default:
          cp++;
          break;
      }
    }
    len = strlen(leaf);
    i = 1;
    while (len > MaxLeafLength) {
      strcpy(leaf + i, leaf + i + 1);
      n += 1;
      len -= 1;
      *(leaf + len) = 0;
      i += 2;
      if (i > len) {
        i = 1;
      }
    }
    *(leaf + MaxLeafLength) = 0;
    fprintf(stderr,"%s\n",leaf);
    if (n > 0 && rest != NULL) {
      sprintf(leaf, "%s%c%s", leaf, FS_DIRSEP, rest);
    }
  }
  return(n);
} /* chktruncate */


void name_to_fs(char *name) {
  char *cp, *leaf, *ext;
  int extlen;

  Buffer[0] = '\0';
  leaf = name;
  ext = NULL;

  for (cp = name; *cp; cp++) {
    if (*cp == UNIX_DIRSEP) {
      *cp = 0;
      cp -= chktruncate(leaf, cp + 1);
      if ((SwapExtensionToDir || SwapInWholePath) && Buffer[0] != '\0') {
        if (SwapInWholePath) {
        }
        Buffer[0] = '\0';
      }
      *cp = FS_DIRSEP;
      leaf = cp + 1;
    } else if (*cp == FS_DIRSEP) {
      if (SwapExtensionToDir || SwapInWholePath) {
        *cp = '\0';
        if (ConvertCompressExtension && *(cp + 1) && strcmp(cp + 1, "Z") == 0) {
          if (Buffer[0] == '\0')
            strcpy(Buffer,leaf);
          strcat(Buffer,CompressExt);
          cp++;
        } else {
          strcpy(Buffer,leaf);
          chktruncate(Buffer, NULL);
          if (PeriodSlashConversion)
            *cp = UNIX_DIRSEP;
          else
            *cp = FS_DIRSEP;
          ext = cp + 1;
        }
      } else if (PeriodSlashConversion) {
        *cp = UNIX_DIRSEP;
      } else {
        *cp = 0;
        cp -= chktruncate(leaf, cp + 1);
        *cp = FS_DIRSEP;
        leaf = cp + 1;
      }
/*
    } else if (PeriodSlashConversion && *cp == '_') {
      *cp = 0;
      strcpy(Buffer,name);
      strcat(Buffer,cp+1);
      strcpy(name,Buffer);
      cp--;
*/
    }
  }
  if ((SwapExtensionToDir || SwapInWholePath) && Buffer[0] != '\0') {
    if (ext != NULL) {
      chktruncate(ext, NULL);
      extlen = strlen(ext);
      strcpy(leaf,ext);
      leaf += extlen;
      *leaf++ = '.';
    }
    strcpy(leaf,Buffer);
    Buffer[0] = '\0';
  }
  chktruncate(leaf,(char *)NULL);
} /* name_to_fs */


static char NameBuffer[9];

char *FileTypeName(int FileType) {
  char *cp;
  os_regset Regs;

  Regs.r[0] = 18;
  Regs.r[2] = FileType;
  do {
  } while (!chkos(os_swix(OS_FSControl, &Regs)));
  cp = NameBuffer;
  *(cp++) = tolower(Regs.r[2] & 0xFF);
  *(cp++) = tolower((Regs.r[2] >>  8) & 0xFF);
  *(cp++) = tolower((Regs.r[2] >> 16) & 0xFF);
  *(cp++) = tolower((Regs.r[2] >> 24) & 0xFF);
  *(cp++) = tolower(Regs.r[3] & 0xFF);
  *(cp++) = tolower((Regs.r[3] >>  8) & 0xFF);
  *(cp++) = tolower((Regs.r[3] >> 16) & 0xFF);
  *(cp++) = tolower((Regs.r[3] >> 24) & 0xFF);
  while (*(--cp) == ' ') ;
  *(++cp) = 0;
  return NameBuffer;
} /* FileTypeName */


void SetFileType(char *FileName, int FileType) {
  os_regset Regs;

  Regs.r[0] = 18;
  Regs.r[1] = (int)FileName;
  Regs.r[2] = FileType;
  chkos(os_swix(OS_File, &Regs));
} /* SetFileType */


void SetAttributes(int Cmd, char *FileName,
                   int Attributes, int LoadAddress, int ExecAddress) {
  os_regset Regs;

  Regs.r[0] = Cmd;
  Regs.r[1] = (int)FileName;
  Regs.r[2] = LoadAddress;
  Regs.r[3] = ExecAddress;
  Regs.r[5] = Attributes;
  chkos(os_swix(OS_File, &Regs));
} /* SetAttributes */
